package kk.learn.scala.work._3

import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer

/**
 * <p>
 *
 * </p>
 *
 * @author KK
 * @since 2021-02-21
 */
/**
 * Duration 作为用户数据时长的数据实体
 */
class Duration(
                val userId: String,
                val positionId: String,
                val startTime: Int,
                var durationMinute: Int
              ) {

  /**
   *
   * @return 一个用于按照用户ID和位置ID分组的字符串
   */
  def userIdAndPositionId: String = userId + "^" + positionId


  override def toString = s"Duration($userId, $positionId, $startTime, $durationMinute)"
}


object Duration {


  def durationStat(data: List[Duration]): List[Duration] = {
    // 对同一个用户，在同一个位置进行分组
    val usersDurations = data.groupBy(_.userIdAndPositionId)


    val result = scala.collection.mutable.Map[String, List[Duration]]()
    for ((userIdPositionId, durations) <- usersDurations) {
      // 排序， 并且转为可变的array
      val sorted = durations.sortBy(_.startTime).toBuffer

      for (i <- 1 until sorted.length) {

        if (canCombine(sorted(i - 1), sorted(i))) {
          // 当需要合并时， 进行合并
          val tmp = combine(sorted(i - 1), sorted(i))
          // 将前一个被合并的元素设置为null， 方便后续步骤移除
          sorted(i - 1) = null
          // 将合并后的元素放置在索引i的位置上
          sorted(i) = tmp
        }
      }

      result.put(userIdPositionId, sorted.toList)
    }

    // 用flatMap展开
    result.flatMap((tuple: (String, List[Duration])) => {
      tuple._2.filter(_ != null)
    }).toList
  }

  def canCombine(left: Duration, right: Duration): Boolean = {
    // 当left和right的时间差， 小于等于left的durationMinute时， 是可以融合的
    val timeGap = (right.startTime - left.startTime) * 60
    if (timeGap <= left.durationMinute) {
      true
    } else {
      false
    }
  }

  def combine(left: Duration, right: Duration): Duration = {
    // 假定不同位置时长记录的停留时间不会重叠， 所以进行简单相加
    left.durationMinute += right.durationMinute
    left
  }

  def main(args: Array[String]): Unit = {

    val testList = (new Duration("UserA", "LocationA", 8, 60)
      :: new Duration("UserA", "LocationA", 9, 60)
      :: new Duration("UserB", "LocationB", 10, 60)
      :: new Duration("UserB", "LocationB", 11, 80) :: Nil)
    println("输出数据：")
    println(testList)
    println("处理结果：")
    println(durationStat(testList))

  }

}
